﻿/*************************************************************************
 * Created by OhZee Creative, LLC
 * 2013
 * This code is licensed under Microsoft Public License (Ms-PL)
 * http://opensource.org/licenses/ms-pl
 * http://ozframework.codeplex.com/
 *************************************************************************/

namespace OhZeeCreative.Xna
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Threading;
    using Microsoft.Xna.Framework.Audio;
    using OhZeeCreative.Sound.Core;
    using OhZeeCreative.WindowsPhone;

    public class SoundRequest
    {
        private static int idCounter;

        public int ID { get; private set; }
        public DateTime Timestamp { get; private set; }
        public SoundItem SoundItem { get; private set;}
        public delegate void StoppedHandler(SoundRequest sender);

        private StoppedHandler stoppedHandler;
        private SoundEffectInstance soundEffectInstance;
        private Timer playTimer;

		public SoundRequest(ISoundItem soundItem)
        {
            this.ID = idCounter++;
            this.Timestamp = DateTime.Now;            
            this.SoundItem = (SoundItem) soundItem;            
        }
        
        public void Play(StoppedHandler handler)
        {
            this.stoppedHandler = handler;
            
            SoundEffect effect = this.SoundItem.SoundEffect;

            if (effect == null)
            {
                this.CallStoppedHandler();
                return;
            }

            this.soundEffectInstance =  effect.CreateInstance();
            //this.soundEffectInstance.Volume = this.SoundItem.Volume * (float)AppSettings.Settings.DefaultAmplification;
            this.soundEffectInstance.Play();
            this.playTimer = new Timer(this.TimerCallback, this, (long)this.SoundItem.Duration.TotalMilliseconds, Timeout.Infinite);            
        }

        public void Stop()
        {
            if (this.playTimer != null)
            {
                this.playTimer.Change(Timeout.Infinite, Timeout.Infinite);
                this.playTimer = null;
            }

            if (this.soundEffectInstance != null)
            {
                this.soundEffectInstance.Stop();             
            }
            this.CallStoppedHandler();
        }

        private void CallStoppedHandler()
        {
            if (this.stoppedHandler != null)
            {
                this.stoppedHandler(this);
            }
        }

        private void TimerCallback(object state)
        {
            SoundRequest soundItem = (SoundRequest)state;
            this.soundEffectInstance.Dispose();
            this.soundEffectInstance = null;
            this.CallStoppedHandler();
        }
    }

    public class SoundManager : ISoundManager
    {
        private object lockObject = new object();
        private List<SoundRequest> playList;
		private IdleDetectionManager idleDetectionManager;

		public SoundManager() : this(null) { }

        public SoundManager(IdleDetectionManager idleDetectionManager)
        {
			this.idleDetectionManager = idleDetectionManager;
            this.playList = new List<SoundRequest>();   
        }

        public bool Play(ISoundItem item)
        {
            if (item == null)
            {                
                return false;
            }

            SoundRequest request = new SoundRequest(item);
            lock (lockObject)
            {
                this.playList.Add(request);                                
            }

			if (this.idleDetectionManager != null)
			{
				this.idleDetectionManager.Push();
			}
            request.Play(this.StoppedHandler);
            return true;
        }

		public bool Stop(ISoundItem item)
        {
            if (item == null)
            {
                return false;
            }                       
                       
            // Don't iterate over playlist directly, because stop handler will modify it.            
            foreach (SoundRequest request in this.playList.ToArray())
            {
                if (request.SoundItem == item)
                {
                    request.Stop();
                }
            }

            return true;
        }

		public int GetPlayingCount(ISoundItem item)
        {
            return this.playList.Where((o) => item == o.SoundItem).Count();
        }

        public void StopAll()
        {
            // Don't iterate over playlist directly, because stop handler will modify it.            
            foreach (SoundRequest request in this.playList.ToArray())
            {
                request.Stop();
            } 
        }

        private void StoppedHandler(SoundRequest request)
        {
            int playingCount;

            lock (this.lockObject)
            {
                this.playList.Remove(request);
                playingCount = this.GetPlayingCount(request.SoundItem);
            }

            Debug.Assert(playingCount >= 0);

            if (playingCount == 0)
            {
                //request.SoundItem.Stopped();
            }

			if (this.idleDetectionManager != null)
			{
				this.idleDetectionManager.Pop();
			}
        }
	}
}
